Enhanced Andean Oscillator 2025 — Smoothed Volatility Envelope Momentum
Table of Contents
Enhanced Andean Oscillator 2025 — Smoothed Volatility Envelope Momentum
This professional-grade momentum oscillator, based on adaptive envelope tracking and volatility projection, is re-engineered from the original Andean Oscillator (by Alpaca Team), with advanced enhancements for 2025 markets.
🔍 What It Does
This indicator dynamically analyzes price momentum using two sets of adaptive envelopes and volatility-weighted deviation calculations. It detects bullish and bearish pressure by projecting variance through a nonlinear smoothing model. Entry and exit signals are filtered using:
- ✅ Double EMA signal smoothing
- ✅ Dead zone filtering (neutral range avoidance)
- ✅ Slope confirmation (momentum acceleration check)
- ✅ Higher timeframe trend alignment (multi-timeframe validation)
Trading Signals
Signal Type | Trigger Condition |
---|---|
Long Entry | Bull > Bear + dead zone AND slope rising AND HTF Bull > Bear |
Short Entry | Bear > Bull + dead zone AND slope falling AND HTF Bear > Bull |
Exit Long | Bull < Signal |
Exit Short | Bear < Signal |
⚙️ Parameters
Name | Description |
---|---|
Base Length | Base envelope smoothing period |
Signal Smoothing | EMA smoothing length (applied twice) |
ATR Length | Used for adaptive alpha calculation |
Volume Lookback | Used to normalize volatility strength |
Slope Lookback | Number of bars for slope confirmation |
Dead Zone Threshold | Minimum deviation between bull/bear required to signal |
Higher Timeframe | Confirms trade signals with higher timeframe momentum |
Visuals
- 🟢 Green Line: Bullish strength
- 🔴 Red Line: Bearish strength
- 🟡 Yellow Line: Smoothed signal
- 🟩 Long Entry marker
- 🟥 Short Entry marker
- ➕ Exit markers for both sides (Red - exit short, green - exit long)
Detailed Technical Specification
Introduction
The original Andean Oscillator is a trend-following technical indicator consisting of two primary lines (a bullish Bull component and a bearish Bear component) and a secondary Signal line (source). A rising Bull line reflects strengthening uptrend momentum, while a rising Bear line reflects strengthening downtrend momentum (source). In the original design, trading signals are derived from crossovers of these lines: for example, a Bull line crossing above the Bear line signals a potential uptrend (buy), and vice versa for a downtrend (sell) (sourcet). The Signal line (typically a smoothed average of the oscillator) helps identify exits or filter noisy signals. This specification outlines an improved version of the Andean Oscillator with enhancements in three key areas: (1) Trend Confirmation & Filters, (2) Signal Enhancements, and (3) Noise Reduction & Smoothing. Each enhancement is always active (no user toggle to disable) and is designed to be efficient so that the final indicator can be implemented within ~200–300 lines of code per platform. All improvements focus on signal accuracy and robustness, avoiding any purely visual features (no additional histograms, shading, or decorative elements). The logic is described in a platform-agnostic manner suitable for TakeProfit’s Indie, Pine Script, MQL (MetaTrader), NinjaScript, ToS (ThinkOrSwim), etc., emphasizing simple arithmetic and built-in functions over complex data structures.
1. Trend Confirmation & Filters
To improve the reliability of the oscillator’s signals, we incorporate several filters that confirm trend context and filter out unfavorable conditions:
1.1 Volume-Weighted Filtering
Rationale: Price movements on high volume tend to indicate genuine shifts in trend momentum, whereas low-volume moves may lack conviction (source). By weighting the oscillator with volume, we ensure that signals sparked by strong participation are emphasized, and weak, low-volume signals are de-emphasized. High trading volume confirms a price move’s strength, while low volume suggests the trend “lacks conviction” (source). Implementation Logic:
- Volume Factor Calculation: Compute a volume factor each bar to quantify volume significance. For example, define
volFactor = currentVolume / avgVolume(N)
, whereavgVolume(N)
is a simple or exponential moving average of volume over the past N bars (N could be the oscillator’s period or a user-defined volume lookback). This yieldsvolFactor > 1
when volume is above average (high participation) and< 1
when below average. - Adaptive Alpha Adjustment: Apply the volume factor to the oscillator’s internal smoothing or calculations. The Andean Oscillator’s Bull and Bear lines are originally derived through an online EMA-like algorithm (using a smoothing factor
α = 2/(period+1)
). We modify this by making α volume-adaptive:- When
volFactor > 1
(high volume), increase the effective α (making the oscillator respond more quickly to price changes). For instance, setα_vol = α * volFactor
(and optionally cap this to avoid extreme values). This causes the envelope calculations for Bull/Bear to give more weight to the current price when volume is high, effectively amplifying the impact of high-volume moves. - When
volFactor < 1
(low volume), decrease α (slower response), e.g.α_vol = α * volFactor
(with volFactor < 1 reducing α). This makes the oscillator less responsive during low-volume periods, filtering out noise from anemic moves.
- When
- Volume Threshold Filter: As an additional simple filter, require a minimum volume condition for trade signals. For example, only act on a Bull vs. Bear crossover if the current volume is above a certain threshold (such as the 50-bar average volume). If volume is below the threshold, signals are considered weak and can be ignored or delayed. This ensures that a crossover accompanied by unusually low volume will not trigger a trade, aligning with the principle that “high volume confirms the price move” (source).
Implementation Notes: These volume adjustments are straightforward in code: computing a moving average of volume and scaling α
each bar requires only a few lines. The volume threshold check is a simple if
condition around signal generation. This keeps the code compact. Volume data is readily available on all platforms (e.g., volume
in Pine, Volume[i]
in MQL), and moving averages can use built-in functions (like ta.sma(volume, N)
in Pine or iMA in MQL). By embedding volume awareness directly into the oscillator’s calculation, we strengthen signal validity without adding significant complexity.
1.2 Higher Timeframe Trend Confirmation
Rationale: Integrating a higher timeframe trend context helps filter out trades that go against the broader trend. A common technique in technical analysis is to use a longer timeframe to confirm signals on a shorter timeframe (Multi-Timeframe Analysis: Basics and Benefits). In practice, if the higher timeframe is in a clear uptrend, one should be biased toward long signals on the lower timeframe, and avoid shorts (and vice versa). This confirmation step improves the probability of success by aligning with the dominant trend (source). Implementation Logic:
- Higher Timeframe Oscillator: Compute the Andean Oscillator’s Bull and Bear components on a higher timeframe (HTF) in parallel with the main (lower timeframe) oscillator. For example, if the primary chart is 5-minute, use a 1-hour oscillator as the confirmer (as suggested). Many platforms support retrieving higher timeframe data within an indicator (e.g., Pine Script’s
request.security()
or MQL’siCustom
/iClose
on higher periods). The HTF oscillator uses the same period settings as the lower timeframe, just applied to higher-period bars. We obtain at least the relationship of the HTF Bull vs. Bear lines (and possibly the HTF Signal line if needed). - Trend Direction Check: Define the higher timeframe trend as bullish if HTF Bull > HTF Bear, or bearish if HTF Bear > HTF Bull. In other words, use the state of the oscillator on the higher chart to gauge the dominant trend direction. This acts as a trend filter.
- Signal Confirmation: Before acting on any crossover signal on the lower timeframe, confirm it aligns with the HTF trend:
- If the lower timeframe gives a Bull crossover (Bull line crossing above Bear line, indicating a long signal), require that the higher timeframe is bullish (HTF Bull > HTF Bear) to validate this signal. If the HTF is bearish or undefined, the long signal is ignored.
- If the lower timeframe gives a Bear crossover (bearish short signal), require HTF Bear > HTF Bull (higher timeframe in downtrend) to proceed.
- This effectively means trades are taken only in the direction of the larger trend. For example, on a 5m vs 1h setup: if the 1-hour Andean Oscillator shows an uptrend (Bull line dominating), then a 5-minute bullish crossover is confirmed and allowed, whereas a 5-minute bearish crossover would be filtered out as counter-trend. This aligns short-term signals with longer-term momentum (source).
Implementation Notes: This requires handling multiple timeframes. In Pine Script, one can use an input (e.g., higher_tf = 60
for 60-minute) and fetch HTF values with request.security(symbol, higher_tf, bull)
and bear
. In MQL, one might call the indicator in the higher timeframe or manually compute a second oscillator using a higher timeframe price series. The added code is moderate but still within limits (essentially duplicating the oscillator calculation for the HTF or using built-ins). The confirmation check is a simple conditional around signal generation. We ensure this feature is always on (no toggle), with perhaps a default higher timeframe multiplier (like 12x the current timeframe) or a fixed value (1H for intraday charts, etc.). This will be built-in but can be exposed as a constant or input if needed (without the ability to disable the check entirely).
1.3 Market Regime Filter (Volatility & Trend Consolidation)
Rationale: Many oscillators give false signals during sideways, low-volatility market conditions (choppy consolidation). To avoid whipsaws, we incorporate a market regime filter that detects when the market lacks a clear trend or sufficient volatility, and suppresses signals during those periods. Two simple ways to gauge regime are using volatility measures (like ATR) and/or the slope of a moving average to judge trend strength. Implementation Logic:
- Volatility Threshold (ATR-Based): Calculate the Average True Range (ATR) over a certain period (e.g., 14 bars) to measure recent volatility. Use a threshold to classify volatility as “low” vs “normal/high”. For example, compute
ATR_val = ATR(14)
and a rolling average of ATR (or use a percentage of price). IfATR_val
is below a predefined threshold (which could be a multiple of a longer-term ATR average or a fraction of current price), then the market is considered to be in a low-volatility consolidation phase. In such a case, temporarily pause new trade signals from the oscillator. The logic is that when ATR is very low, the price is moving in a tight range, so Bull/Bear crossovers are likely insignificant noise. Only when volatility picks up (ATR exceeds the threshold) do we trust the oscillator’s signals again. This acts as a volatility filter for the signals (example) (similar in spirit to avoiding trades inside the “dead zone” around a flat market, see Dead Zone below).- Example: If using a 14-period ATR, we might set the threshold as, say, the 50-period average ATR * 0.5. If current ATR(14) < 0.5 * ATR(50), we flag “consolidation mode” and ignore crossovers. Once ATR(14) rises back above that level, normal signals resume. (The exact parameters can be tuned; the key is we have an objective volatility cutoff.)
- Moving Average Slope Filter: As an alternative or complementary approach, measure the slope of a longer-term moving average of price to gauge trend direction vs. flatness. For instance, take a 50-bar EMA of price. Compute its slope over the last few bars (e.g., difference between its current value and its value 10 bars ago, normalized by price or by ATR). If the slope is near zero (i.e., the MA is essentially flat), it indicates no strong trend (sideways market). In such cases, oscillator signals are likely to whipsaw and thus can be ignored. We only trade when the long MA has a clear upward or downward slope beyond a minimum angle/threshold. This is effectively a trend filter: ensure there is a trending bias in price before trusting oscillator signals.
- Implementation: Calculate
slope = (MA_now - MA_prev) / MA_prev
(or simply the absolute difference) and compare to a small threshold. If|slope| < S
(S = small threshold like 0.1% or a value corresponding to a very shallow angle), treat the market as flat/consolidating and suspend new entries. If the slope magnitude exceeds S, the market has a directional bias and signals are allowed.
- Implementation: Calculate
- Combined Regime Logic: We can use either or both of the above measures. A robust approach is to require both adequate volatility and directional bias for signals. For example, define a boolean
trending_ok = (ATR_val >= ATR_thresh) AND (|slope| >= S)
. Only iftrending_ok
is true do we act on Bull/Bear crossovers. This ensures we are out of very low volatility and there is at least some trend. Alternatively, a simpler implementation is to pick one method (ATR or slope) as the primary regime filter for simplicity.
Note: These regime filters are always on in the improved oscillator (no manual toggle). They are simple calculations: ATR is often built-in (one line function) and an MA slope check is just a subtraction. They do not require large loops or memory. By filtering out consolidation phases, we significantly reduce false signals. This idea parallels the concept of using ADX in other systems to avoid low-trend phases; here we specifically gave the choice of ATR or MA slope. The developer may implement whichever is easier given the platform (ATR is commonly available and fits well since we use ATR again for adaptive smoothing below). The net effect is the oscillator will only generate trade signals in a trending, volatile market environment, staying silent during sideways markets – a prudent enhancement to improve signal quality (source).
2. Signal Enhancements
The following improvements focus on refining the signals generated by the oscillator, making them smarter and more robust. This includes automatic detection of classic divergence patterns, ensuring crossover strength, and smoothing techniques for stability.
2.1 Divergence Detection (Bullish & Bearish)
Rationale: Divergences between price and an oscillator are well-known predictors of potential reversals (Bullish Divergences and Bearish Reversal Signals). A bullish divergence occurs when price makes a lower low but the oscillator makes a higher low, indicating weakening downside momentum (Bullish Divergences and Bearish Reversal Signals). A bearish divergence is the opposite: price makes a higher high while the oscillator’s corresponding peak is lower, signaling weakening upside momentum. By detecting basic divergences between price action and the Andean Oscillator’s Bull/Bear lines, the indicator can provide early warning of trend shifts or at least flag that a current signal may be suspect (if accompanied by divergence). Implementation Logic:
- Identify Local Extrema: Continuously monitor for recent price peaks and troughs and corresponding oscillator peaks and troughs. One simple approach is to use a rolling window or pivot detection function: for example, consider a bar a local high if its close (or high) is greater than those of a few bars before and after; similarly, a local low if it’s lower than a few bars around it. Many platforms have built-ins (e.g.,
ta.pivothigh
/ta.pivotlow
in Pine) to detect such pivots. Alternatively, one can track when the price has changed direction from up to down (marking a top) or down to up (marking a bottom). Do this both for the price series and for the oscillator values (we can use the main oscillator line or specifically the Bull/Bear lines or even the difference between them). - Store Last Two Extrema: Keep track of the last two significant pivot highs and lows for both price and the oscillator. For instance, maintain variables for the last confirmed swing high and the one before it, and similarly for swing lows. Likewise for oscillator: perhaps use the Signal line or the dominant of Bull/Bear at the time as the oscillator reading to compare (or even use the Bull line for peaks in uptrends, Bear line for troughs in downtrends).
- Divergence Check: When a new extreme is identified, check for a divergence condition with the previous extreme:
- Bullish Divergence: If a new price low is lower than the previous notable low, but the oscillator’s corresponding low is higher than its previous low, flag a bullish divergence signal (source). In practical terms, let
price_low2 < price_low1
andosc_low2 > osc_low1
(whereprice_low1/osc_low1
are the earlier low values, andprice_low2/osc_low2
the latest). This condition suggests price made a new low with diminishing bearish momentum on the oscillator – a potential upward reversal setup (source). The indicator can highlight this by, for example, printing an alert or marker on the chart or internally tagging the next Bullish crossover as higher-probability. - Bearish Divergence: If a new price high is higher than the previous swing high, but the oscillator’s high is lower than its prior peak, we have a bearish divergence (price uptrend weakening) (source). In formula:
price_high2 > price_high1
andosc_high2 < osc_high1
. This warns of a possible downward reversal ahead.
- Bullish Divergence: If a new price low is lower than the previous notable low, but the oscillator’s corresponding low is higher than its previous low, flag a bullish divergence signal (source). In practical terms, let
- Usage of Divergence Signal: The indicator can incorporate divergence information in a couple of ways:
- Confirmation/Warning: Use divergence as a confirmation or contradiction to the oscillator’s own signals. For example, if a bullish crossover occurs and a bullish divergence was recently identified, that adds confidence to the buy signal (since momentum shift aligns with price pattern). Conversely, if a bullish crossover occurs but a bearish divergence is present (price made a high but oscillator lagged), the trader should be cautious – the up move may be exhausted. The code can set a flag like
bullish_divergence = true/false
andbearish_divergence = true/false
, updated whenever conditions are met, which can then be displayed or used to qualify signals (e.g., require no bearish divergence against a long entry, etc., or simply inform the user). - Standalone Alert: The indicator could also optionally output a separate indication (like an arrow or message) when a divergence is detected, independent of the crossover signals. However, since we avoid additional visual elements as per constraints, we likely limit it to influencing the logic of signals rather than drawing new objects.
- Confirmation/Warning: Use divergence as a confirmation or contradiction to the oscillator’s own signals. For example, if a bullish crossover occurs and a bullish divergence was recently identified, that adds confidence to the buy signal (since momentum shift aligns with price pattern). Conversely, if a bullish crossover occurs but a bearish divergence is present (price made a high but oscillator lagged), the trader should be cautious – the up move may be exhausted. The code can set a flag like
- Efficiency Considerations: Divergence detection needs only a small lookback and a few variables for last extrema, keeping code short. We avoid extensive array searching by using simple pivot detection or a fixed number of bars to look back for highs/lows. For example, always comparing the most recent pivot against the prior one means we don’t need to store long histories, just update two sets of values when a new pivot forms. This keeps memory use minimal. The logic is essentially a few
if
statements whenever a new pivot is identified.
By embedding divergence analysis, the improved oscillator gains an early reversal detection mechanism. This helps in qualifying signals: e.g., a bullish divergence often “indicates bears are losing power and bulls are ready to control the market” (source), so a subsequent Bull crossover is more credible. On the other hand, spotting a divergence can also warn against false breakouts if the oscillator isn’t confirming the price’s extremes. This feature enriches the indicator’s decision-making without requiring user intervention.
2.2 Slope-Based Signal Strength Confirmation
Rationale: Not all crossover signals are equal – some occur with strong momentum (steeply rising/falling lines), while others happen when the lines are flat and merely drifting across each other. A steep slope in the Bull/Bear lines at the moment of crossover indicates a more decisive move, whereas a flat crossover often leads to whipsaws (false signals) (source). Thus, we enhance the signal logic to confirm that the crossing happens with sufficient line slope or “angle”, filtering out weak crossovers. Implementation Logic:
- Slope Calculation: Quantify the slope or rate-of-change of the oscillator lines around the crossover point. There are multiple ways to do this:
- Compute the first derivative of the Bull and Bear lines. For example,
slope_bull = bull(current) - bull(N bars ago)
, where N is a small number (could be 1 for a simple difference per bar, or a few bars to smooth noise). Similarlyslope_bear = bear(current) - bear(N bars ago)
. These values indicate how fast each line is moving up or down. We could also annualize or scale it to an “angle” if needed, but a relative threshold is sufficient. - Another approach is to look at the difference line (Bull minus Bear). When Bull crosses Bear upward, the difference (Bull – Bear) goes from negative to positive. The steepness of this cross can be gauged by how quickly that difference is changing. For instance,
slope_diff = ( (Bull - Bear) now - (Bull - Bear) a few bars ago )
. A rapid change means a steep cross.
- Compute the first derivative of the Bull and Bear lines. For example,
- Angle Threshold: Define a minimum acceptable slope/angle for a valid crossover signal. For example, we might require that at the time of a bullish cross,
slope_bull > X
andslope_bear < -Y
(with X, Y being small positive values) to confirm that Bull is rising and Bear is falling at a noticeable rate. If instead both lines are flat (slope near zero) and just entangled, the signal is ignored as it lacks momentum. This concept is analogous to requiring a certain angle threshold – we essentially create a minimum slope criterion to “filter low-angle false signals” (source).- In more concrete terms, suppose we use one-bar differences: if Bull crosses above Bear but
bull[i] ≈ bull[i-1]
(little change) andbear[i] ≈ bear[i-1]
, then skip it. Ifbull[i]
is significantly greater thanbull[i-1]
(indicating a jump) at the cross, that’s a positive sign. We could set X as a fraction of the Bull/Bear’s recent range or a small percentage of price to be scale-aware.
- In more concrete terms, suppose we use one-bar differences: if Bull crosses above Bear but
- Implementation in Code: Each bar, when checking for a crossover condition (e.g.,
if (bull > bear and bull[1] <= bear[1])
for a bullish cross this bar), add an additional check:and (bull - bull[2] > slopeMin)
and(bear - bear[2] < -slopeMin)
(here using 2 bars ago for a slightly broader slope). Alternatively, maintain a short EMA of the Bull line’s derivative and ensure it’s above 0 by a margin. The exact method can be tuned, but the principle is the same: confirm a robust upward trajectory for Bull line and downward for Bear line on a long signal, and vice versa for a short. If these conditions are not met, label the crossover as “weak” and do not trigger a trade. - Avoiding Flat Signals: By doing this, the oscillator effectively ignores those times when Bull and Bear lines weave closely together (sign of consolidation or indecision), only responding when a clear separation is starting. In other words, the angle threshold plus dead zone (next section) together ensure trades are taken after the lines have meaningfully diverged beyond a flat zero-cross region (source).
This slope filter improves the quality of entries. It ensures that we only trade when momentum is on our side. The concept is similar to waiting for a MACD line to separate from the signal line by a certain amount or an ADX rising – here we directly use the slope of our oscillator components. The coding overhead is low (a few arithmetic operations and comparisons). We make these thresholds built-in (not user-adjustable to adhere to “no optional toggles”), choosing reasonable defaults (perhaps based on backtesting or typical scale of the oscillator). The result is that the improved Andean Oscillator will avoid “flat” crossovers, reducing false signals in sideways or weak-momentum situations.
2.3 Double-Smoothed Signal Line
Rationale: To further strengthen the signal component and reduce noise, we apply double smoothing to the Signal line. Double-smoothing is a technique where an already smoothed value is smoothed again, yielding an even more stable output. This is inspired by indicators like the Double Smoothed Stochastic, which achieve a “more refined and less volatile signal” through two layers of smoothing (source). In our context, the Signal line (which helps identify trend confirmation and exits) will benefit from reduced whipsaws after double smoothing, making it more robust in identifying genuine trend changes. Implementation Logic:
- Original Signal Calculation: In the base oscillator, the Signal line is typically an EMA of the dominant component or of the Bull/Bear values. For example, the original code had
signal = EMA( max(bull, bear), signalLength )
. This produces a single-smoothed signal line that lags the faster Bull/Bear lines slightly and can be used as a trigger or filter (e.g., Bull crossing below its Signal line indicates a waning uptrend (source)). - Apply a Second Smoothing: We will take the output of that first smoothing and apply another moving average on top of it. In practice:
- Compute the initial signal as usual (e.g.,
signal1[i] = EMA(basis, K)
wherebasis
might bemax(bull, bear)
or some combination, and K is the signal period). - Then compute
signal2[i] = EMA(signal1, K2)
to get the final Signal line. We could use the same period for the second EMA (K2 = K) to truly double-smooth with equal weight, or use a shorter period for the second stage if we want to slightly reduce lag. A simple choice is to use the same length twice for consistency. This effectively means the final Signal line is an EMA of an EMA.
- Compute the initial signal as usual (e.g.,
- Benefits: The double-smoothed signal will be smoother than a single EMA of the data, filtering out short-lived fluctuations. It provides a clearer reference for trend direction. For example, if using it as an exit: instead of a tight trailing signal line that might cause premature exits on minor pullbacks, the double EMA signal will stick longer with the trend and only reverse when a more significant momentum shift occurs. In effect, it “dampens” the sensitivity of the signal line just enough to ignore trivial moves, focusing on sustained shifts. This aligns with the goal of a refined signal: the double smoothing “provides a more refined and less volatile signal” (source) as noted in other double-smoothed indicators.
- Crossover Logic Unchanged: All existing rules that involve the signal line (like Bull crossing below Signal to exit a long, etc.) remain the same, but now use the new double-smoothed
signal2
. Becausesignal2
is smoother, crosses between Bull/Bear and this Signal will occur slightly later than with a raw single EMA, but will be more reliable. The minor increase in lag is a reasonable trade-off for the reduction in noise. - Implementation: Most platforms have an EMA function. We can simply call it twice. For instance, in PineScript:
sig1 = ta.ema(basis, lengthSig); sig2 = ta.ema(sig1, lengthSig)
. In MQL: first loop to calculate sig1, then loop again for sig2 (or use built-in iMA twice). This likely adds only a few lines. It’s also possible to combine into one formula if needed, but two steps are clearer. The code stays well within limits. Double smoothing is always on – we don’t provide an option to revert to single smoothing (per the constraint that improvements are not optional).
In summary, the double-smoothed Signal line will act as a stable guide for confirming trends and exits. By reducing choppiness, it complements the earlier improvements: we’ve made the raw Bull/Bear signals more responsive to volume and momentum, and concurrently made the Signal line a bit slower and steadier. This combination yields an oscillator that responds to true signals but remains calm during noise, improving overall signal-to-noise ratio.
3. Noise Reduction & Smoothing
The final set of enhancements explicitly target noise reduction and adaptability of the oscillator. We introduce an ATR-based adaptive smoothing, a dead zone for tiny oscillations, and an option for alternative smoothing methods. These changes ensure the indicator can adapt to different market conditions and further minimize false triggers, all while keeping the calculation efficient.
3.1 ATR-Adaptive Smoothing Factor
Rationale: Markets alternate between high volatility (big moves) and low volatility (quiet periods). A fixed smoothing factor (α) for the oscillator may be too slow during fast-moving markets or too jittery during calm markets. By linking the smoothing factor to the Average True Range (ATR) – a direct measure of volatility – we can make the oscillator adaptive: speed up in volatile conditions and slow down in quiet conditions. This concept is akin to the Adaptive Moving Average (AMA) which “changes its sensitivity to price moves depending on the calculated volatility” (source). Implementation Logic:
- Calculate ATR: Use a moderate period for ATR (e.g., 14 or 20) to represent current volatility. ATR is typically available via built-in function (
ta.atr
in Pine,iATR
in MQL). We will use the current ATR value (and possibly compare it to a longer-term ATR average or reference) to adjust smoothing. - Base Smoothing Factor: The base Andean Oscillator uses an exponential smoothing factor
α = 2/(N+1)
for a given period N. For example, if period N=50, α≈0.039. This α determines how fast the envelopes (up1, dn1, etc.) react to new prices – higher α means more weight to recent price (faster response, less smoothing), lower α means more lag (slower, more smoothing). - Volatility Scaling: Define a way to modulate α by ATR. One simple scheme:
- Compute a volatility ratio:
volRatio = ATR(current) / ATR_ref
. HereATR_ref
could be a longer-term average of ATR (say 50-bar SMA of ATR) or perhaps ATR on a higher timeframe or simply a fixed value representing “normal” volatility for the asset.volRatio > 1
means volatility is above average,volRatio < 1
means below average. - Define adaptive α:
α_adapt = α * volRatio^β
, where β is a tuning exponent (possibly β=1 for linear scaling, or 0.5 for a more tempered scaling using square root). The idea is that when volatility is high (volRatio > 1), α_adapt > α (we allow the indicator to react faster), and when volatility is low, α_adapt < α (we smooth more). We might also impose bounds to keep α_adapt within (0,1). For example, if volRatio = 2 (volatility double normal), α_adapt might be roughly double the base α (if β=1). If volRatio = 0.5 (volatility half), α_adapt becomes half the base α, etc. - Another approach: directly adjust the effective period N based on ATR. For instance, define
N_adapt = N / volRatio
(so high vol reduces the period, making the EMA faster, and low vol increases period making it slower). Then compute α_adapt = 2/(N_adapt+1). This achieves a similar result in perhaps a more bounded way.
- Compute a volatility ratio:
- Apply to Oscillator Calculation: Use
α_adapt
in the recursive formulas for the oscillator’s internal envelopes (up1, up2, dn1, dn2
in the original code). For example, the original had:up1[i] = max( max(Close, Open), max( up1[i-1] - (up1[i-1] - Close)*α , Close ) )
. We replace the constant α with α_adapt (computed fresh each bar based on ATR). Thus, on a volatile bar, α_adapt is larger, so the term(up1[i-1] - Close)*α_adapt
subtracts more, pullingup1
down faster towards the price – meaning the Bull/Bear lines will adjust quickly to sharp moves. In a quiet period, α_adapt is tiny, so the envelopes barely move, meaning the oscillator stays steadier and ignores small wiggles. - Effect: This adaptivity allows the Andean Oscillator to behave more like a fast indicator in fast markets and a slow, smooth indicator in slow markets, achieving a balance. It reduces lag during high volatility (capturing big moves early) and reduces noise during low volatility (not overreacting to tiny moves). Essentially, the oscillator becomes “self-tuning” to market volatility.
- Comparison: Traditional AMA implementations often use price volatility or an efficiency ratio; here we simplify by using ATR directly. The concept is the same as in the Thinkorswim AMA study: “a moving average that changes its sensitivity to price moves depending on volatility” (source) – we are applying that principle to our oscillator’s smoothing.
Implementation Notes: ATR calculation is straightforward and adds minimal overhead (one value per bar). The α adjustment is one or two extra arithmetic operations in the main loop. Ensure to initialize properly and possibly smooth ATR itself if too erratic (maybe use a short MA of ATR to avoid jitter in α). This feature is always on, with default parameters set internally (e.g., 14 for ATR, etc.). No complex data structures are needed, just the last ATR and maybe an ATR average. This adaptive smoothing works hand-in-hand with the earlier volume weighting and regime filter: volume weighting and ATR adaptation both adjust responsiveness, but based on different factors (volume vs price range). Together they make the oscillator highly responsive to significant, volatile moves and very cautious during quiet times, which is ideal for noise reduction.
3.2 Dead Zone Threshold for Weak Crossovers
Rationale: We introduce a small “dead zone” around the equilibrium of the Bull and Bear lines where minor fluctuations are ignored. This is a common technique to avoid trading on negligible differences that don’t signify a real trend bias (source). By requiring the Bull and Bear lines to separate beyond a certain tiny range, we ensure that we only act when a meaningful divergence appears, not just when lines kiss each other back and forth. Implementation Logic:
- Threshold Definition: Choose a small threshold value
δ
that represents a negligible oscillator difference. This could be a fixed number (e.g., 0.1 if the oscillator is scaled in certain units) or relative (e.g., 5% of the oscillator’s recent average range, or perhaps tied to ATR as a percentage of price). The threshold should be small enough to not miss real signals, but large enough to cover the typical noise oscillation when the market is flat. For example, if historically Bull-Bear difference oscillates within ±0.2 with no trend, we might set δ = 0.2. - Dead Zone Implementation: Modify the crossover conditions to include this buffer:
- For a Bullish indication, instead of checking
bull > bear
, requirebull > bear + δ
. The Bull line must exceed the Bear line by more than δ to be considered truly above. - For a Bearish indication, require
bear > bull + δ
(equivalentlybull < bear - δ
) to consider it a genuine cross under. - If the lines are within
δ
of each other (i.e.,|bull - bear| < δ
), we treat it as essentially no definitive trend – this is the “dead zone” where the oscillator is saying the trend is flat/indecisive. In that state, no new trade signal is triggered.
- For a Bullish indication, instead of checking
- Hysteresis: The dead zone creates a slight hysteresis in signals, which is actually beneficial. For example, if bull is just 0.05 above bear and δ = 0.1, it won’t signal long yet; it waits until bull is sufficiently higher. Once a signal is given and if bull later falls but remains within 0.1 of bear, we don’t immediately flip to a short until it clearly goes beyond – this prevents quick flip-flopping on minor moves. Essentially, it demands a clear lead by one line over the other.
- Justification: This aligns with what some oscillators do by having a neutral band around zero. The TradingView “EMA Slope/Angle” script, for instance, plotted a dead zone around the zero line so that trades are only taken after that zone is crossed (source). In our case, zero line equivalent is bull == bear. We are ensuring the cross is beyond a tiny zone around that line, which filters out weak crossovers as intended (source).
- Integration with Slope Filter: The slope filter (2.2) and dead zone (3.2) work together: the dead zone stops extremely tight crosses, while the slope filter stops very flat angled crosses. Both conditions will often coincide, but each addresses a slightly different aspect. We implement both for thoroughness. The dead zone is simpler – just an offset in the comparison – and ensures even if the slope was briefly nonzero, we don’t act unless the separation is clear.
Implementation: Just incorporate δ into the conditional checks for bull/bear crosses. For example, pseudocode for long entry condition might become: if (bull > bear + δ and bull_prev <= bear_prev + δ): signalLong();
. This adds only a constant or a tiny calculation. δ can be defined at top as a constant or computed from ATR/volatility (for adaptivity). Given the constraint of no user toggles, δ will be a fixed built-in parameter (perhaps determined via testing; e.g., 0.1 or 0.2 in oscillator units, or maybe something like 0.05 * ATR of the last X bars to scale with volatility). Even if δ is static, it should be small.
In summary, the dead zone creates a small buffer to ignore indecisive oscillations, thereby reducing false signals. The lines must “commit” to a direction beyond this buffer to trigger a trade. This improvement is conceptually simple but powerful in choppy markets, and it’s very lightweight to implement.
3.3 Alternative Smoothing Method (EMA vs. RMA)
Rationale: The default oscillator uses Exponential Moving Averages (EMA) for smoothing the internal calculations (Bull/Bear envelopes and the Signal line). We introduce the ability to use an alternative smoothing method – specifically Wilder’s smoothing (RMA) – as an option for these calculations. Different smoothing algorithms can slightly alter the responsiveness vs. stability trade-off. Wilder’s moving average (also known as RMA or SMMA) gives a bit more weight to older values compared to EMA of the same period (source). For example, a 14-period Wilder’s MA is roughly equivalent to a 27-period EMA in terms of smoothness ( source). By allowing EMA or RMA, the indicator can be tuned to the developer’s or trader’s preference for smoothness without adding complexity in use (it’s a one-time choice built into the code or via a simple input). Implementation Logic:
- Envelope Smoothing Choice: In the calculation of the Bull and Bear components, the core mechanism is an online recursive averaging. By default we treat it as EMA (with α as derived earlier). To implement Wilder’s smoothing instead, we would use a formula akin to:
newValue = oldValue + (1/N) * (raw - oldValue)
(Wilder’s formula uses 1/N as the coefficient). In our code, this translates to using a different α. For a given period N, EMA uses α = 2/(N+1), whereas Wilder’s RMA uses α = 1/N (source). We can thus allow switching α’s definition:- If method = EMA:
α = 2/(N+1)
(as before). - If method = RMA:
α = 1/N
. (Note: To closely match Wilder’s original, one might also seed the initial value as a simple average of first N points, but in long runs it won’t matter much.) - With this change, the rest of the envelope formula (for up1, up2, etc.) remains the same, but the behavior changes slightly: RMA will update more slowly for the same N, meaning Bull/Bear lines will be smoother and lag a bit more compared to EMA. EMA reacts faster to recent price changes.
- If method = EMA:
- Signal Line Smoothing Choice: Similarly, for the Signal line, we can offer smoothing by EMA or RMA. For example, the default might be
signal = EMA(X, sigLen)
. If RMA is selected, we computesignal = RMA(X, sigLen)
(with X typically being max(Bull, Bear) or some combined series). Wilder’s smoothing will make the signal line a bit more damped compared to EMA of equal length. -
Selection Mechanism: Since we avoid UI complexity, this could be hard-coded or set via a simple constant or input variable (e.g.,
useWilder = true/false
). In Pine Script, one could implement a toggle input likeinput.method = "EMA" or "Wilder"
(though that technically is an input toggle, it doesn’t disable a feature, just chooses a variant – this should be acceptable given the requirement for a simple toggle for this purpose). In MQL, one might do it via an extern enum or just by providing two versions of the code (less ideal). The simplest is a conditional branch in the code:if (smoothingMethod == RMA) alpha = 1/period; else alpha = 2/(period+1);
Then use
alpha
in calculations. Likewise for the signal line:if (smoothingMethod == RMA) signal = prevSignal + (1/sigLen)*(X - prevSignal); else signal = EMA(X, sigLen); // or similar
(In Pine we can utilize
ta.rma()
for Wilder andta.ema()
for EMA directly for clarity). - Always Active: This feature doesn’t add or remove signals; it just alters the smoothing style. We consider it an improvement in flexibility. We will pick one as the default (likely EMA to maintain original behavior), but the code is structured so that one can easily switch to Wilder’s by changing a flag. Because the specification says all improvements are always active, one interpretation is that we should not allow the user to disable volume filter or divergence, etc. This smoothing method, however, is more of a configuration option than an on/off feature – providing it via a code parameter is reasonable. If needed, it can be locked to one choice; but we mention it so that across different platforms, the developer knows they can implement either smoothing.
- Why RMA: Wilder’s smoothing is used in RSI, ATR, ADX calculations, known for its stability. It effectively results in a longer effective period than EMA (source), thus producing smoother lines. Some traders might prefer the Andean Oscillator with this characteristic (fewer whipsaws, at the cost of slightly more lag). Others might prefer the quicker EMA version. The improved oscillator code can accommodate both with minimal changes.
By including an alternative smoothing option, we future-proof the indicator for different use cases without exceeding the complexity budget. This addition requires only a few extra lines (to choose the α and possibly an if/else for the signal calculation), and no heavy computations. We will default to EMA for consistency with the original, but highlight in documentation that a Wilder’s smoothing option exists if one wants an even smoother oscillator output.
Implementation Considerations & Constraints
The above enhancements collectively create a more reliable Andean Oscillator while respecting the given constraints:
- Code Compactness: All features are designed to be implemented in a compact form. We leverage built-in functions (for ATR, moving averages, higher timeframe data, etc.) wherever possible to keep code length within 200–300 lines per platform. There are no large loops beyond the indicator’s main per-bar calculation, and no extensive data storage (we use only a handful of variables for things like last pivots for divergence). This ensures the final script is efficient and not overly verbose. For example, divergence detection uses only recent pivots, volume filtering uses a simple moving average of volume, etc., avoiding arrays or buffers that would bloat the code.
- Always-On Enhancements: Each improvement is integrated into the core logic without external toggles. The user cannot turn these features off – they are part of the “improved” indicator’s behavior by default. This simplifies the interface and ensures the oscillator consistently applies all safety checks. The only minor configurable aspect is the smoothing method (EMA/RMA) which can be selected via a code parameter if desired, but there is no option to disable the volume filter, divergence check, etc. They are inherently applied to all signals. This meets the requirement that no optional settings sections are added; the oscillator always uses the enhanced logic.
- No Visual Gizmos: We have explicitly avoided adding any decorative chart elements like shaded areas, histograms, or multi-colored ribbons. The indicator output remains essentially the three lines (Bull, Bear, Signal) or a variant thereof. We may add subtle markers for divergence if absolutely necessary (for instance, a small dot or triangle when divergence is detected) but even that can be omitted or kept minimal as an alert mechanism. The focus is on logic improvements, not visual ones. This keeps the indicator visually clean and the code free of lengthy plotting instructions. (If the platform allows, one could note divergence or trend filter status via color changes of the lines or small labels, but again, that’s optional visualization outside the scope of this spec.)
- Performance: None of the added features should significantly impact performance. Volume and ATR calculations are O(1) per bar. The higher timeframe confirmation effectively doubles calculations (computing oscillator twice), but given the simplicity of the oscillator math, this is still lightweight (and in many cases, platforms handle multi-timeframe efficiently by internally caching the HTF series). The divergence check adds a few comparisons. Overall, the improved indicator remains real-time friendly and avoids deeply nested loops or anything that would slow down processing of incoming ticks.
- Summary of Signal Logic with Improvements:
- Compute Bull/Bear with volume-weighted, ATR-adaptive smoothing (taking into account current volume and volatility each bar).
- Compute Signal (double-smoothed, using chosen method EMA/RMA).
- Determine if market regime is acceptable (volatility and trend slope filters). If not, skip signal generation this bar (possibly set an output state like “noTrend” or simply do nothing unless conditions clear).
- Check for Bull/Bear crossover beyond dead zone and with sufficient slope:
- If Bull crosses above Bear (and difference > δ) and slopes are steep, and higher timeframe trend is bullish, then trigger a Bullish signal (e.g., trend change to up). If any of those conditions fail, no signal (the crossover is ignored as weak or unconfirmed).
- If Bear crosses above Bull (with > δ separation) and slopes steep, and HTF trend is bearish, trigger a Bearish signal.
- Mark any divergence conditions found; if a divergence contradicts the signal, one might choose to downgrade the signal strength or issue a caution (this part can be left to user interpretation or used as an additive filter – e.g., require no bearish divergence present for a long entry unless we want to be very strict).
- Use the Signal line for exits or additional filtering: e.g., only consider a trend truly reversed when Bull (or Bear) also crosses the Signal line, etc., as per original usage rules (source), but now the Signal line is more robust due to double smoothing.
By following this specification, developers will create an improved Andean Oscillator that is more adaptive, confirms with broader context, and filters out false signals. All of this is achieved without sacrificing the indicator’s original purpose of gauging trend direction and momentum. The improved version will help traders “buy low and sell high” with greater confidence by ensuring that each signal is backed by volume, aligned with the higher trend, not occurring in a dead market, and is technically strong (steep and non-divergent). These enhancements transform the Andean Oscillator into a more comprehensive trading tool while keeping it implementable in simple trading scripting languages. Sources: The design draws on established trading principles and analogs in technical analysis literature, such as volume-confirmed trends (1), multi-timeframe confirmation (2), momentum divergences (3), slope/angle filters (4), double smoothing techniques (5), and volatility-adaptive indicators (6), all of which have been incorporated to enhance the oscillator’s performance in various market conditions.
Final code
TakeProfit’s Indie Script version
PineScript Version
Strategy Version for Backtesting
✅ Consistency Review: Indie vs Pine Script code
Component | Pine Script Behavior | Your Indie Version | ✅/⚠️/❌ | Notes |
---|---|---|---|---|
Envelope Calculation (up1/dn1) | Recursive with var and up1[1] references |
✅ MutSeriesF with self.up1[1] , initialized in __init__ |
✅ | Fully consistent, persistent across bars. |
Envelope Calculation (up2/dn2) | Same as above, squared prices | ✅ Implemented with c2 , o2 , and persistent MutSeriesF |
✅ | Matches original logic. |
ATR Calculation | atr_now = ta.atr(...) , atr_ref = ta.sma(atr_now, ...) |
✅ Correctly using Atr.new(...) and Sma.new(...) |
✅ | Perfect match. |
Adaptive Alpha | alpha = max(min(...), 0.001) |
✅ Identical formula used | ✅ | Consistent. |
Volume Factor | volFactor = volume / avgVol |
✅ Same logic with zero check | ✅ | ✔ Safe division included. |
Bull/Bear Strength | sqrt(max(...)) * volFactor |
✅ Matched exactly | ✅ | Fully aligned. |
Signal (double EMA) | signal = ta.ema(ta.ema(max(bull, bear), len), len) |
✅ Ema.new() double-smoothed |
✅ | 100% match. |
Slope Logic | slopeBull = bull - bull[slopeLookback] etc. |
✅ Correct indexing with self.bullSeries[...] |
✅ | Verified functional. |
Dead Zone Filter | abs(diff) < deadZone |
✅ Implemented as-is | ✅ | Good. |
HTF Confirmation | request.security(..., bull) and compare bull > bear |
✅ Uses calc_on(AndeanHTF) for full bull/bear calc on HTF |
✅ | Correct pattern. ⚠ You may later want to test multi-timeframe behavior thoroughly. |
Long/Short Conditions | All combined logical checks | ✅ Exactly matches Pine structure | ✅ | ✔ No logic missing. |
Exit Conditions | exitLong = bull < signal etc. |
✅ Implemented 1:1 | ✅ | ✔ |
Position State Tracking | Implicit in Pine with conditions | ✅ Explicit with inLong , inShort series |
✅ | Excellent addition for marker tracking. |
Long/Short Entry Markers | bgcolor + alertcondition() |
✅ Replaced with upward/downward triangle markers | ✅ | ✅ Great solution given Indie limitations. |
Exit Markers | alertcondition(exitLong) etc. |
✅ Cross markers used based on exit + active state | ✅ | Correct translation. |
Background Coloring | bgcolor(color.new(...)) |
❌ Not possible in Indie yet → replaced | ✅ | ✅ Good workaround. |
alertcondition() Support | Built-in in Pine | ⚠️ Not implemented in Indie | ⚠️ | ❓ Indie currently lacks native alertcondition —future enhancement? |
NaN Handling (first bar init) | na(up1[1]) ? init : ... |
✅ Checked with isnan(...) or not isnan(...) |
✅ | ✔ Stable start. |
Marker Text/Labels | Uses label.new() in Pine (optionally) |
✅ Uses plot.Marker(..., text="▲") style |
✅ | Clear and practical. |